package com.example.axon.web;


import com.example.axon.commands.AddCmd;
import com.example.axon.commands.CreateCmd;
import com.example.axon.commands.SubtractCmd;
import com.example.axon.commands.TransferOutCmd;
import com.example.axon.utils.IdUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.axonframework.commandhandling.*;
import org.axonframework.commandhandling.gateway.CommandGateway;
import org.axonframework.queryhandling.QueryGateway;
import org.springframework.data.domain.Example;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * Created by mavlarn on 2018/5/22.
 */
@RestController
@RequestMapping("/account")
@Api(tags = "4: AccountController")
@Slf4j
@AllArgsConstructor
public class AccountController {

    private CommandGateway commandGateway;
    private CommandBus commandBus;
    private QueryGateway queryGateway;
    private AccountRepository accountRepository;

    @PostMapping("")
    @ApiOperation("createAccount")
    public CompletableFuture<Object> create(@RequestParam String name, @RequestParam String password) {
        log.info("Request to create account for: {}", name);
        CreateCmd cc = CreateCmd.builder()
                .accountId(name)
                .password(password)
                .balance(0D)
                .userName(name)
                .build();

        return commandGateway.send(cc);
    }

    @PutMapping("/{accountId}/deposit/{amount}")
    @ApiOperation("depositMoney")
    public CompletableFuture<Object> depositMoney(@PathVariable String accountId, @PathVariable Double amount) {
        log.info("Request to depositMoney {} from account {} ", amount, accountId);
        AddCmd cc = AddCmd.builder()
                .accountId(accountId)
                .balance(amount)
                .build();
        return commandGateway.send(cc);
    }

    @PutMapping("/{accountId}/withdraw/{amount}")
    @ApiOperation("withdrawMoney")
    public CompletableFuture<Object> withdrawMoney(@PathVariable String accountId, @PathVariable Double amount) {
        log.info("Request to withdraw {} from account {} ", amount, accountId);
        return commandGateway.send(SubtractCmd.builder().accountId(accountId).balance(amount));
    }


    @GetMapping("/{accountId}")
    @ApiOperation("getAccountById")
    public AccountEntity getAccountById(@PathVariable String accountId) {
        log.info("Request Account with id: {}", accountId);
        AccountEntity ce = new AccountEntity();
        ce.setAccountId(accountId);
        return accountRepository.findOne(Example.of(ce)).orElseGet(null);
    }

    /**
     * 查询的是物化视图，非事件 eventStore
     */
    @GetMapping("")
    @ApiOperation("getAllAccounts")
    public List<AccountEntity> getAllAccounts() {
        log.info("Request all Accounts");
        return accountRepository.findAll();
    }

    /**
     * 查询的是物化视图，非事件 eventStore
     */
    @PostMapping("transfer")
    @ApiOperation("transfer")
    public CompletableFuture<Object> transfer(String fromId, String toId, Double amount) {

        log.info("Request all Accounts");
        return commandGateway.send(TransferOutCmd.builder()
                .fromId(fromId)
                .amount(amount)
                .toId(toId)
                .accountId(fromId)
                .txId(IdUtils.getUuid())
                .balance(amount)
                .build()
        );
    }

//    /**
//     * 仅仅在测试环境中使用如下查询方式（axon 会（聚合）执行所有的 event），查询的是 eventStore
//     */
//    @GetMapping("/query")
//    @ApiOperation("queryOnlyInTestEvn")
//    public Account queryOnlyInTestEvn(AccountId customerId) throws ExecutionException, InterruptedException {
//        return queryGateway.query(customerId, Account.class).get();
//    }
}
